import cherrypy
import sqlite3
import time

from postmarkup import render_bbcode

import Common

class Thread(Common.Template):
	# Call the default function with no arguments
	def index(self):
		return self.default()
	index.exposed = True

	# Default function displays a given thread.  
	def default(self, id = None):	
		# Get the thread name
		thread_name = self.get_thread_name(id)
		
		if self.Thread_Closed(id):
			thread_name += " - CLOSED"
		
		if thread_name == None:
			yield self.error("The specified thread does not exist!", True)	
		else:
			# The thread exists				
			
			# Print the top of the page
			yield self.header(thread_name)
			yield self.links()
			yield self.breadcrumbs(ThreadID = id)
			yield '<br />'
			
			# Print the action buttons
			yield self.generator_expand(self.action_buttons(id))
				
			# Print the posts
			yield self.generator_expand(self.post_list(id))
					
			# Print the action buttons again
			yield self.generator_expand(self.action_buttons(id))
			
			# Print the footer
			yield self.footer()
			
			# The page was viewed, so increment the viewcount
			cursor = cherrypy.thread_data.db.cursor() 	
			cursor.execute("UPDATE Thread SET ViewCount = ViewCount + 1 WHERE ID = ?", (id,))
			cherrypy.thread_data.db.commit()		
	default.exposed = True
	
	# The action buttons are reply and the moderator actions.  This function
	# takes a given ID and prints the actions for that thread, respecting
	# the permisisons of the logged in user
	def action_buttons(self, id):
		if self.getLoginID() != None:
			yield "<p align='right'>"
			if self.hasPermission(id):
				# If the user is a mod in this given subforum, print the 
				# moderator action buttons
				
				# Determine if the given thread is stickied to figure out
				# what value to give the sticky function
				cursor = cherrypy.thread_data.db.cursor() 	
				cursor.execute("SELECT Thread.Sticky FROM Thread WHERE Thread.ID = ?", (id,))
				Sticky = cursor.fetchone()[0]
				
				if Sticky == 0:
					yield "<a href='Sticky/%s/1'>Sticky Thread</a> | " % id
				else:
					yield "<a href='Sticky/%s/0'>Unsticky Thread</a> | " % id
				
				# Determine if the given thread is closed to figure out
				# what value to give the close function
				if self.Thread_Closed(id):
					yield "<a href='Closed/%s/0'>Open Thread</a> | " % id
				else:
					yield "<a href='Closed/%s/1'>Close Thread</a> | " % id
					
				# Print the Move and Delete buttons
				yield "<a href='Move/%s'>Move Thread</a> | " % id
				yield "<a href='Delete/%s'>Delete Thread</a><br />" % id			
			if self.Thread_Closed(id) == False:
				# If the thread isn't closed, print the reply button
				yield "<a href='/Post/New/%s'>New Reply</a>" % id
			yield "</p>"		
	
	# This function prints all of the posts in a given thread
	def post_list(self, id):	
		# We actually need two cursors for this view
		cursor = cherrypy.thread_data.db.cursor() 	
		cursor2 = cherrypy.thread_data.db.cursor() 		
		
		# Get all the posts in this thread, sorted by ascending post ID (chronological order)		
		cursor.execute('''
			SELECT 
				Post.ID, Post.Title, Post.Content, Post.Timestamp, User.ID, User.Username, User.Permission, User.Avatar, User.Signature, Post.EditTimestamp, Post.EditUserID
			FROM
				Post, User
			WHERE
				Post.ThreadID = ? AND
				Post.UserID = User.ID
			ORDER BY 
				Post.ID ASC
			''', (id,))
		
		# Print the post, each in a separate table
		count = 1
		# An enum of the different permisison levles
		permissions = ["Administrator", "Moderator", "Member"]
		
		# If the user is logged in, we need an extra row for the reply with
		# quote button.
		if self.getLoginPermission() <= 2:
			rowspan = 4
		else:
			rowspan = 3
		
		# Print each post
		for ID, Title, Content, Timestamp, UserID, Username, Permission, Avatar, Signature, EditTimestamp, EditUserID in cursor.fetchall():
			yield "<table width='100%' cols='2' class='thread' >"
			yield "<tr>"
			yield "<td class='thread' colspan='2'><a name='%s'></a>%s <span style='float:right; text-align: right;'><a href='#%s'>#%s</a></span></td>" % (ID, Title, ID, count)
			yield "</tr>"
			yield "<tr>"
			# If avatar is not set, print a 100x100 blank div, otherwise, print the image
			if Avatar == "" or Avatar == None:
				yield "<td class='thread' rowspan='%s' width='200px'><a href='/User/%s'>%s</a><br />%s<br /><div width='100px' height='100px'>&nbsp;</div></td><td class='thread' height='75px' >%s</td>" % (rowspan, UserID, Username, permissions[Permission], render_bbcode(Content))
			else:
				yield "<td class='thread' rowspan='%s' width='200px'><a href='/User/%s'>%s</a><br />%s<br /><img src='/%s' width='100px' height='100px' /></td><td class='thread' height='75px' >%s</td>" % (rowspan, UserID, Username, permissions[Permission], Avatar, render_bbcode(Content))
			yield "</tr>"
			yield "<tr>"
			# Print the bbcode-ized sig
			yield "<td class='thread'>%s</td>" % render_bbcode(Signature)
			yield "</tr>"
			yield "<tr>"
			if EditTimestamp == None:
				# The post hasn't been editted, just print the timestamp
				yield "<td class='thread'>Posted on %s</td>" % time.strftime("%c", time.localtime(Timestamp))
			else:
				# The post has been editted, get the editing user's name
				cursor2.execute('''SELECT User.Username FROM User WHERE User.ID = ?''', (EditUserID,))
				EditUsername = cursor2.fetchone()[0]
				yield "<td class='thread'>Posted on %s, Last Edited on %s by %s</td>" % (time.strftime("%c", time.localtime(Timestamp)), time.strftime("%c", time.localtime(EditTimestamp)), EditUsername)
			yield "</tr>"
			# If the thread isn't closed, print the reply buttons
			if self.Thread_Closed(id) == False and self.getLoginPermission() <= 2:
				yield "<tr>"
				yield "<td class='thread' align='right'>"
				if self.getLoginPermission() <= 1 or self.getLoginID() == UserID:
					yield "<a href='/Post/Edit/%s'>Edit</a> " % ID
				if self.getLoginPermission() <= 2:
					yield "<a href='/Post/Reply/%s/%s'>Reply with Quote</a>" % (id, ID)
				yield "</td>"
				yield "</tr>"
			yield "</table>"
			yield "<br />"
			count = count + 1
	
	# This function is what creates new threads.  If title and content aren't
	# set, the form is showed.  Otherwise, the new thread and new post
	# are created
	def New(self, subforum_id, title = "", content = ""):		
		# Get the thread name
		subforum_name = self.get_subforum_name(subforum_id)
		
		title = title.strip()
		content = content.strip()
		
		if self.getLoginPermission() >= 3:				
			yield self.error("You are not logged in", True)	
		elif subforum_name == None and subforum_id != "NULL":
			yield self.error("Specified subforum doesn't exist", True)
		elif title != "" and content != "":
			cursor = cherrypy.thread_data.db.cursor() 
		
			# This PRAGMA is needed to ensure recursive triggers work
			cursor.execute("PRAGMA recursive_triggers = 1;")
			cherrypy.thread_data.db.commit()
			
			# Add the Thread
			cursor.execute('''
				INSERT INTO Thread (ID, SubforumID, PostCount, ViewCount, Sticky, Closed)
				VALUES (NULL, ?, 0, 0, 0, 0)
				''', (subforum_id,))
			cherrypy.thread_data.db.commit()
			
			thread_id = cursor.lastrowid
			
			# Add the Post
			cursor.execute('''
				INSERT INTO Post (ID, Title, Content, Timestamp, UserID, ThreadID, EditTimestamp, EditUserID)
				VALUES (NULL, ?, ?, ?, ?, ?, NULL, NULL)
				''', (self.strip_html_bbcode(title), content, int(time.time()), self.getLoginID(), thread_id,))						
			cherrypy.thread_data.db.commit()
			
			# After this commit, the post counts will update because of the triggers
			
			# Redirect back to the thread at the new post location
			yield self.redirect("/Thread/%s" % thread_id)
		else:					
			# Show the create thread form
			yield self.header("New Thread in %s" % subforum_name)
			yield self.links()
			yield self.breadcrumbs(SubforumID = subforum_id)
			
			yield "<form method='post' action='/Thread/New'>"
			yield "Thread Title: <br />"
			yield "<input class='monospace' type='text' name='title' size='60' value='%s' /><br />" % title
			yield "Content: <br />"
			yield "<textarea class='monospace' name='content' rows='20' cols='80'>%s</textarea><br />" % content
			yield "<input type='hidden' readonly='readonly' name='subforum_id' value='%s'>" % subforum_id
			yield "<input type='submit' value='New Thread' />"
			yield "</form>"
			
			yield self.footer()
	New.exposed = True	
	
	# This function sets or unsets the Sticky attribute for a given thread
	def Sticky(self, id, value):
		if self.hasPermission(id):
			cursor = cherrypy.thread_data.db.cursor() 
			
			cursor.execute("UPDATE Thread SET Sticky = ? WHERE ID = ?", (value, id,))
			cherrypy.thread_data.db.commit()
			
			# Redirect back to the thread at the new post location
			yield self.redirect("/Thread/%s" % (id))
		else:			
			# Not an admin, error
			yield self.error('You do not have permission to view this page!', True)
	Sticky.exposed = True
	
	# This function sets or unsets the Closed attribute for a given thread
	def Closed(self, id, value):
		if self.hasPermission(id):
			cursor = cherrypy.thread_data.db.cursor() 
			
			cursor.execute("UPDATE Thread SET Closed = ? WHERE ID = ?", (value, id,))
			cherrypy.thread_data.db.commit()
			
			# Redirect back to the thread at the new post location
			yield self.redirect("/Thread/%s" % (id))
		else:			
			# Not an admin, error
			yield self.error('You do not have permission to view this page!', True)
	Closed.exposed = True
	
	# This function moves a given thread.  If NewParentID isn't set, the form
	# is displayed, otherwise, the thread is moved
	def Move(self, id, NewParentID = None):		
		if self.hasPermission(id) and NewParentID == None:
			# show the move form
			
			yield self.header("Move Thread")
			yield self.links()
			yield self.breadcrumbs(ThreadID = id)
			
			yield "<p>"
			yield "<form method='post' action='%s'>" % id
			yield self.RelocateTree()
			yield "<br /><br /><input type='submit' value='Move Thread' />"
			yield "</form>"
			yield "</p>"
		
			yield self.footer()
		elif self.hasPermission(id):
			# Move the thread
			
			cursor = cherrypy.thread_data.db.cursor() 
			
			# This PRAGMA is needed to ensure recursive triggers work
			cursor.execute("PRAGMA recursive_triggers = 1;")
			cherrypy.thread_data.db.commit()	
			
			cursor.execute("UPDATE Thread SET SubforumID = ? WHERE ID = ?", (NewParentID, id,))
			cherrypy.thread_data.db.commit()
			
			# Triggers will delete posts and update post/thread counts
		
			yield self.redirect("/Thread/%s" % (id))		
		else:			
			# Not an admin, error
			yield self.error('You do not have permission to view this page!', True)
	Move.exposed = True		
	
	# This function recursively builds the tree of the available subforums
	def RelocateTree(self, id = "", depth = ""):		
		if id == "" and depth == "":
			out = "<select name='NewParentID'><option value='NULL' style='font-style: italic;'>(Forum Root)</option>" + self.RelocateTree("NULL", "&mdash;") + "</select>"	
		else:
			cursor = cherrypy.thread_data.db.cursor() 	
			cursor.execute("SELECT ID, Name FROM Subforum WHERE ParentSubforumID IS ?", (id,))
			
			out = ""
			for ID, Name in cursor.fetchall():
				out += "<option value='%s'>%s%s</option>" % (ID, depth, Name)			
				out += self.RelocateTree(ID, depth + "&mdash;")		
			
		return out
	
	# This function deletes the thread with the given id.  Triggers will take
	# care of the posts contained in the thraed
	def Delete(self, id):
		if self.hasPermission(id):
			cursor = cherrypy.thread_data.db.cursor() 
			
			cursor.execute("SELECT Thread.SubforumID FROM Thread WHERE Thread.ID = ?", (id,))
			SubforumID = cursor.fetchone()[0]
			
			# This PRAGMA is needed to ensure recursive triggers work
			cursor.execute("PRAGMA recursive_triggers = 1;")
			cherrypy.thread_data.db.commit()
			
			cursor.execute("DELETE FROM Thread WHERE ID = ?", (id,))
			cherrypy.thread_data.db.commit()
			
			# Triggers will delete posts and update post/thread counts
			
			# Redirect back to the thread at the new post location
			yield self.redirect("/Subforum/%s" % (SubforumID))
		else:			
			# Not an admin, error
			yield self.error('You do not have permission to view this page!', True)
	Delete.exposed = True
